﻿using Acl;
using Acl.Collections;
using Acl.Log;
using Acl.WinFormHosting;

using Microsoft.Win32;

using System.Text;
using System.Windows.Forms.Integration;

namespace WinFormHostingDemo.Services;

static class LoggerNames
{
    public const string Platform = "平台";
}
class WinFormService : BooleanDisposable, IWinFormsService
{
    /// <summary>
    /// 通知程序使用了WPF。
    /// 如果删除此定义，则程序在DPI为125%的情况下界面显示异常。
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
    private readonly ElementHost _hostMute = new ElementHost();

    public WinFormService()
    {
        Application.ThreadException += OnApplicationThreadException;
        Application.ApplicationExit += OnApplicationExit;
        AppDomain.CurrentDomain.UnhandledException += OnDomainUnhandledExceptionOccurs;

        SubscribeSystemEvents();
        // 
        ProductCache.ThresholdWaring += ProductCache_ThresholdWaring;
    }

    public void Initialize()
    {

    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Application.ThreadException -= OnApplicationThreadException;
            Application.ApplicationExit -= OnApplicationExit;
            AppDomain.CurrentDomain.UnhandledException -= OnDomainUnhandledExceptionOccurs;

            UnsubscribeSystemEvents();
            ProductCache.ThresholdWaring += ProductCache_ThresholdWaring;
        }
        base.Dispose(disposing);
    }

    static void ProductCache_ThresholdWaring(object? sender, EventArgs<IProductCache> e)
    {
        var cache = e.Data;
        if (CanTraceThresholdWaringLog(cache))
        {
            var sb = new StringBuilder(512);
            sb.AppendFormat("[{0}].[{1}]生产者线程 产生阈值预警事件,生成产品数量已达到:{2}。上次入队的类型：{3}\r\n",
                 Thread.CurrentThread.Name,
                 Thread.CurrentThread.ManagedThreadId,
                 cache.Count,
                 cache.LastAddedProduct.GetType().Name);
            sb.AppendFormat("\t[{0}].[{1}]-消费者线程上次耗时:{2}, 本次耗时:{3},正在消费的产品数量：{4},正在消费的产品类型：{5}, 堆栈信息:\r\n\t{6}",
                     e.Data.Thread.Name,
                     e.Data.Thread.ManagedThreadId,
                     e.Data.ConsumerState.LastElapsedMilliseconds,
                      (DateTime.Now - e.Data.ConsumerState.StartTime).TotalMilliseconds,
                      cache.CurrentProducts.Length,
                      cache.CurrentProducts[0].GetType().Name,
                      e.Data.ConsumerState.StackTrace);

            LogManager.GetLogger(LoggerNames.Platform).Warn(sb.ToString());
        }
    }

    /// <summary>
    /// 预警日志打印策略：检测队列数量对报警阈值的取余数操作，等于0，或者50 打印，其它不打印
    /// </summary>
    private static bool CanTraceThresholdWaringLog(IProductCache cache)
    {
        uint div = cache.WarningThreshold <= 50 ? cache.WarningThreshold : 50;

        // 如果余数为0那么能够整除，则打印。
        return (cache.Count % div) == 0;
    }

    static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
    {
        LogManager.GetLogger(LoggerNames.Platform)
            .Warn(string.Format("收到用户挂起或继续系统事件，电源事件模式类型={0}", e.Mode));
    }

    static void OnSessionSwitch(object sender, SessionSwitchEventArgs e)
    {
        LogManager.GetLogger(LoggerNames.Platform)
               .Warn(string.Format("更改当前登录的Windows用户，事件类型={0}", e.Reason));
    }

    static void OnSessionEnded(object sender, SessionEndedEventArgs e)
    {

        LogManager.GetLogger(LoggerNames.Platform)
            .Warn(string.Format("用户注销或关闭操作系统，事件类型={0}", e.Reason));
    }

    /// <summary>
    /// 订阅OS事件。
    /// </summary>
    private static void SubscribeSystemEvents()
    {
        SystemEvents.PowerModeChanged += OnPowerModeChanged;
        SystemEvents.SessionSwitch += OnSessionSwitch;
        SystemEvents.SessionEnded += OnSessionEnded;
    }

    /// <summary>
    /// 订阅OS事件。
    /// </summary>
    private static void UnsubscribeSystemEvents()
    {
        SystemEvents.PowerModeChanged -= OnPowerModeChanged;
        SystemEvents.SessionSwitch -= OnSessionSwitch;
        SystemEvents.SessionEnded -= OnSessionEnded;
    }

    /// <summary>
    /// OnApplicationExit
    /// </summary>
    private static void OnApplicationExit(object? sender, EventArgs e)
    {
    }

    /// <summary>
    /// 捕捉当前应用程序域未处理的错误
    /// </summary>
    private static void OnDomainUnhandledExceptionOccurs(object sender, UnhandledExceptionEventArgs args)
    {
        try
        {
            string info = string.Format("AppDomain（ID={0}，Name={1}）Thread（ID={2}，Name={3}）中未处理的异常。\r\n{4}",
                AppDomain.CurrentDomain.Id,
                AppDomain.CurrentDomain.FriendlyName,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.Name,
                (Exception)args.ExceptionObject);

            LogManager.GetLogger(LoggerNames.Platform).Error(info);

            MessageBox.Show(info, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        catch
        {
        }
    }

    /// <summary>
    /// 在发生未捕获线程异常时发生
    /// </summary>
    private static void OnApplicationThreadException(object sender, ThreadExceptionEventArgs args)
    {
        try
        {
            string info = string.Format("Thread（ID={0}，Name={1}）程序中未捕获的线程异常。\r\n{2}",
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.Name,
                args.Exception);

            LogManager.GetLogger(LoggerNames.Platform).Error(info);

            MessageBox.Show(info, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        catch
        {
        }
    }
}
